package me.seawenc.datastash;


import me.seawenc.datastash.outputs.AbstractConsumer;
import me.seawenc.datastash.helper.FileHelper;
import me.seawenc.datastash.inputs.AbstractProducer;

import java.io.File;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Optional;
import java.util.Properties;

/**
 * 数据地图客户端
 */
public class DatastashApplication {
    // 控制程序是否正常运行
    public static boolean isRunning=true;

    // 需要执行外脚本路径，
    public static void main(String[] args) throws Exception {
        help(args);
        // 设置程序停止回调
        addShutdownHook();
        // 从配置文件中获取参数
        Properties props = getExtFileConfig(args);
        //数据输出者
        AbstractConsumer tcpConsumer = getOutputInstance(props);
        //数据输入者
        AbstractProducer producer = getInputInstance(props);
        // 开启生产消息，转发给consumer
        producer.producer(tcpConsumer);
    }

    private static void help(String[] args) {
        // fixme 从参数中识别出帮助指令，完成后退出程序
    }

    private static void addShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            DatastashApplication.isRunning=false;
            System.out.println("程序接收到关闭指令,正在停止程序...");
        }));
    }

    /**
     * 获得消息生产者实例
     * @param props
     * @return
     * @throws Exception
     */
    private static AbstractProducer getInputInstance(Properties props) throws Exception {
        String input = props.getProperty("input");
        if(input==null){
            throw new IllegalArgumentException("配置文件中未配置‘input’参数");
        }
        String classFullPath= getCurrentPackage()+".inputs."+input.toLowerCase()+"."+input+"Producer";
        AbstractProducer instance = getInstance(classFullPath, props, AbstractProducer.class);
        return instance;
    }

    /**
     * 获得消费者实例
     * @param props
     * @return
     * @throws Exception
     */
    private static AbstractConsumer getOutputInstance(Properties props) throws Exception {
        String output = props.getProperty("output");
        if(output==null){
            throw new IllegalArgumentException("配置文件中未配置‘output’参数");
        }
        String classFullPath= getCurrentPackage()+".outputs."+output.toLowerCase()+"."+output+"Consumer";
        AbstractConsumer consumer= getInstance(classFullPath,props, AbstractConsumer.class);
        return consumer;
    }

    private static <T> T getInstance(String clazzFullPath, Properties props, Class<T> clazz) throws Exception {
        Class<?> targetClazz;
        try {
            targetClazz = Class.forName(clazzFullPath);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("未找到类："+clazzFullPath+",应该是‘output’或`input`参数错误!");
        }
        Constructor<?> constructor = targetClazz.getConstructor(Properties.class);
        Object target = constructor.newInstance(props);

        return (T)target;
    }

    private static String getCurrentPackage() {
        String name = DatastashApplication.class.getName();
        return name.replace("."+ DatastashApplication.class.getSimpleName(),"");
    }

    private static Properties getExtFileConfig(String[] args) throws Exception {
        String confKey="DATASTASH_CONF_PATH";
        Optional<String> pathOptional = Arrays.stream(args)
                .filter(p -> p.contains(confKey + "="))
                .map(p -> p.replace(confKey + "=", "")).findFirst();

        String confPath=pathOptional.isPresent()?pathOptional.get():"config/datastash.properties";
        if(!new File(confPath).exists()){
            throw new RuntimeException("未找到配置脚本文件："+confPath+",可设置启动参数修改默认值，例：`java -jar dataforward.jar DATAFORWARD_CONF_PATH=/opt/app/dataforward/conf.properties`修改此路径");
        }
        Properties props = FileHelper.readExtResFile(confPath);
        return props;
    }
}
